package sgsi.model.alocacion;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import sgsi.model.entidades.Palet;
import sgsi.model.entidades.TipoDePalet;
import sgsi.model.entidades.espacios.Ubicacion;

public class CriterioOrdenUbicacionesPorAjuste implements CriterioOrdenUbicaciones {

	private int paletsParaAlocar;
	private TipoDePalet tipoDePalet;
	private float alto;
	private float peso;
	
	public void initCriterio(List<Palet> palets) {
		// Seteo los datos iniciales (para palets homogeneos)
		paletsParaAlocar = palets.size();
		tipoDePalet = palets.get(0).getTipoDePalet();
		alto = palets.get(0).getAltura();
		peso = palets.get(0).getPeso();
	}
	
	public List<Ubicacion> ordenarUbicaciones(Set<Ubicacion> ubicacionesSinOrdenar) {
		List<Ubicacion> ubicacionesConMayorCapacidad = new ArrayList<Ubicacion>();
		List<Ubicacion> ubicacionesConCapacidadNecesaria = new ArrayList<Ubicacion>();
		List<Ubicacion> ubicacionesConMenorCapacidad = new ArrayList<Ubicacion>();
		
		Iterator<Ubicacion> iterarUbicaciones = ubicacionesSinOrdenar.iterator();
		while (iterarUbicaciones.hasNext()) {
			Ubicacion ubicacion = iterarUbicaciones.next();
			
			int paletsQuePuedeAlocar = ubicacion.cantidadDisponiblePara(tipoDePalet, alto, peso);
			
			if (paletsQuePuedeAlocar > paletsParaAlocar)
				ubicacionesConMayorCapacidad.add(ubicacion);
			else if (paletsQuePuedeAlocar == paletsParaAlocar)
				ubicacionesConCapacidadNecesaria.add(ubicacion);
			else
				ubicacionesConMenorCapacidad.add(ubicacion);
		}
		
		//Primero devuelvo las ubicaciones para la cantidad exacta
		if (ubicacionesConCapacidadNecesaria.size() > 0) {
			ordenarListaPorCodigo(ubicacionesConCapacidadNecesaria);	
			return ubicacionesConCapacidadNecesaria.subList(0, 1);
		}
		
		//Segundo devuelvo la primer ubicacion con cantidad mayor
		if (ubicacionesConMayorCapacidad.size() > 0) {
			ordenarListaAscendente(ubicacionesConMayorCapacidad);
			return ubicacionesConMayorCapacidad.subList(0, 1);
		}
		
		//Tercero devuelvo la primer ubicacion con cantidad mayor
		ordenarListaDescendente(ubicacionesConMenorCapacidad);					
		return ubicacionesConMenorCapacidad;
	}
	
	@SuppressWarnings("unchecked")
	private void ordenarListaAscendente(List<Ubicacion> ubicaciones) {
		Collections.sort(ubicaciones, new Comparator() {
			public int compare(final Object objeto1, final Object objeto2) {
				final Ubicacion ubicacion1 = (Ubicacion) objeto1;
				final Ubicacion ubicacion2 = (Ubicacion) objeto2;
				
				final Integer cantidad1 = ubicacion1.cantidadDisponiblePara(tipoDePalet, alto, peso);
				final Integer cantidad2 = ubicacion2.cantidadDisponiblePara(tipoDePalet, alto, peso);
				
				final Integer codigoUbicacion1 = ubicacion1.getCodigoUbicacion();
				final Integer codigoUbicacion2 = ubicacion2.getCodigoUbicacion();
				
				final Integer comparacion = cantidad1.compareTo(cantidad2);
				if (comparacion == 0)
					return codigoUbicacion1.compareTo(codigoUbicacion2);
				
				return comparacion;	
			}
		});		
	}
	
	@SuppressWarnings("unchecked")
	private void ordenarListaPorCodigo(List<Ubicacion> ubicaciones) {
		Collections.sort(ubicaciones, new Comparator() {
			public int compare(final Object objeto1, final Object objeto2) {
				final Ubicacion ubicacion1 = (Ubicacion) objeto1;
				final Ubicacion ubicacion2 = (Ubicacion) objeto2;
				
				final Integer codigoUbicacion1 = ubicacion1.getCodigoUbicacion();
				final Integer codigoUbicacion2 = ubicacion2.getCodigoUbicacion();
				
				return codigoUbicacion1.compareTo(codigoUbicacion2);					
			}
		});		
	}
	
	@SuppressWarnings("unchecked")
	private void ordenarListaDescendente(List<Ubicacion> ubicaciones) {
		Collections.sort(ubicaciones, new Comparator() {
			public int compare(final Object objeto1, final Object objeto2) {
				final Ubicacion ubicacion1 = (Ubicacion) objeto1;
				final Ubicacion ubicacion2 = (Ubicacion) objeto2;
				
				final Integer cantidad1 = ubicacion1.cantidadDisponiblePara(tipoDePalet, alto, peso);
				final Integer cantidad2 = ubicacion2.cantidadDisponiblePara(tipoDePalet, alto, peso);
				
				final Integer codigoUbicacion1 = ubicacion1.getCodigoUbicacion();
				final Integer codigoUbicacion2 = ubicacion2.getCodigoUbicacion();
				
				if (cantidad1 < cantidad2)
					return 1;
				
				if (cantidad1 > cantidad2)
					return -1;
				
				if (codigoUbicacion1 > codigoUbicacion2)
					return 1;
					
				return -1;					
			}
		});		
	}	
}
